<?php
namespace Blockgolde\HyperfBusinessWrapper\Utils;

use Blockgolde\HyperfBusinessWrapper\Constants\ErrorCode;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;

/**
 * API请求返回服务类
 */
class Response
{
    private $http_code = 200;

    /**
     * http头部信息
     *
     */
    private $http_headers = [
    ];

    /**
     * 业务返回码
     *
     */
    private $business_code = 200;

    /**
     * 业务返回消息
     *
     */
    private $business_msg = 'SUCCESS';

    /**
     * @Inject
     * @var ResponseInterface
     */
    protected ResponseInterface $response;

    /**
     * 设置http状态码
     *
     * @param int $code
     *
     * @return $this
     */
    public function setHttpCode(int $code = 200): self
    {
        $this->http_code = $code;

        return $this;
    }

    /**
     * 设置http头部信息
     *
     * @param string $name
     * @param mixed  $value
     *
     * @return $this
     */
    public function setHttpHeader(string $name, $value): self
    {
        $this->http_headers[$name] = (string)$value;

        return $this;
    }

    /**
     * 成功数据返回
     *
     * @param mixed $data           返回数据
     * @param int   $business_code  业务返回码
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */
    public function success($data, int $code = 200)
    {
        $this->business_code = $code;

        return $this->response($data);
    }

    /**
     * 失败返回
     *
     * @param string $error_msg      错误信息
     * @param mixed  $data           返回数据
     * @param int    $business_code  错误业务码
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */
    public function fail(string $error_msg = 'fail', $data = null, int $business_code = 999999)
    {
        $this->business_code = $business_code;
        $this->business_msg = $error_msg;

        return $this->response($data);
    }

    /**
     * 返回数据
     *
     * @param $data
     *
     * @return ResponseInterface|\Psr\Http\Message\ResponseInterface
     */
    private function response($data)
    {
        $this->response = $this->response->json($this->normalizeData($data))->withStatus($this->http_code);

        if (! empty($this->http_headers)) {
            foreach ($this->http_headers as $name => $value) {
                $this->response = $this->response->withHeader($name, $value);
            }
        }

        return $this->response;
    }

    /**
     * @param     $data
     * @param int $statusCode
     *
     * @return PsrResponseInterface
     *
     * raw返回
     */
    public function raw($data, int $statusCode = 200): PsrResponseInterface
    {
        return $this->response->raw($data)->withStatus($statusCode);
    }

    public function file(string $absolutePath, string $fileName): PsrResponseInterface
    {
        return $this->response->download($absolutePath, $fileName)->withStatus(200);
    }

    /**
     * 标准化返回数据格式
     *
     * @param mixed $data  业务返回数据
     *
     * @return array
     */
    private function normalizeData($data): array
    {
        return [
            'code'      => $this->business_code,
            'data'      => $data,
            'message'   => $this->business_msg
        ];
    }
    
    /**
     * @param   int     $code
     * @param   string  $msg
     * @param   null    $data
     *
     * @return string
     */
    public static function responseJson(int $code, string $msg, $data = null): string
    {
        $result = ['code' => $code, 'message' => $msg];
        is_null($data) or $result['data'] = $data;
        return json_encode($result, JSON_UNESCAPED_UNICODE);
    }

    public static function notFound(): string
    {
        return self::responseJson(
            ErrorCode::INTERNAL_ERROR,
            ErrorCode::getMessage(ErrorCode::INTERNAL_ERROR)
        );
    }

    public static function methodNotAllowed(): string
    {
        return self::responseJson(
            ErrorCode::METHOD_NOT_ALLOWED,
            ErrorCode::getMessage(ErrorCode::INTERNAL_ERROR),
            ErrorCode::getMessage(ErrorCode::METHOD_NOT_ALLOWED)
        );
    }
}